// $Id: physicsmanager.cpp 470 2008-05-27 16:27:22Z agjermun $
// Implementation of the physicsmanager
//
// ml278
// Copyright (C) 2008 Bjørn Øivind Bjørnsen, Aleksander Gjermundsen, Knut Andre Tidemann, Thomas Hansen
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#include "physicsmanager.h"
#include "physicsinfo.h"
#include "colladaphysicsloader.h"
#include <vector>
#include <stdexcept>
#include "Ogre.h"
#include <btBulletCollisionCommon.h>

template<> PhysicsManager* Ogre::Singleton<PhysicsManager>::ms_Singleton = 0;

PhysicsManager::PhysicsManager()
{
}

PhysicsManager::~PhysicsManager()
{
}

/**
 * Creates a rigid body based on the specifications provided
 * @param mass the mass of the rigid body. If 0, the rigid body is static.
 * @param colShapeKey reference to a ColShapeKey to provide a collision shape, must be valid, results undefined if null
 * @param localInertia the local inertia to apply to the rigid body
 * @param startTransform the starting transform to apply to the rigid body
 *
 * @returns a PhysicsInfo object with the information specified
*/
PhysicsInfo getPhysicsInfo(btScalar &mass, ColShapeManager::ColShapeKey &colShapeKey, btVector3 &localInertia,
		btTransform &startTransform)
{
	// create rigid body here
	// get collision shape
	// get motionstate
	// create rigidbody
	// add to vector
	// return
	ColShapeManager *csMgr = ColShapeManager::getSingletonPtr();
	btCollisionShape *colShape = csMgr->getShape(colShapeKey);

	colShape->calculateLocalInertia(mass,localInertia);

	btDefaultMotionState *motionState = new btDefaultMotionState(startTransform);
	btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,motionState,colShape,localInertia);
	btRigidBody *body = new btRigidBody(rbInfo);

	vector<btRigidBody*> object;
	object.push_back(body);

	PhysicsInfo pInfo(object);
	return(pInfo);
}

/**
 * Attempts to load a given collada file and extract the physics information within
 * @param colladaFile the collada file to attempt to load
 * @note this is very basic and slightly hackish, it only loads the collada file, grabs all the rigidbodies within
 *	 and adds them to a PhysicsInfo object. It is the user of these methods responsibility to make sure that this is
 *	 actually what they want.
 * @returns a PhysicsInfo object with the information embedded in the collada file
*/
PhysicsInfo getPhysicsInfo(String colladaFile)
{
	// create temp dynamics world
	// setup loader here
	// grab rigidbodies from dynamics world
	// add to vector
	// return vector
	vector<btRigidBody*> object;
	
	// XXX: heavy operation
	// create default configuration for memory and collision
	btDefaultCollisionConfiguration *collisionConfiguration = new btDefaultCollisionConfiguration();

	// use the default dispatcher
	btCollisionDispatcher *dispatcher = new btCollisionDispatcher(collisionConfiguration);

	// Set the min and max size of the world
	btVector3 worldAabbMin(-10000,-10000,-10000);
	btVector3 worldAabbMax(10000,10000,10000);
	btBroadphaseInterface *overlappingPairCache = new btAxisSweep3(worldAabbMin,worldAabbMax,4096);

	// set the default constraint solver
	btSequentialImpulseConstraintSolver *sol = new btSequentialImpulseConstraintSolver;

	btDynamicsWorld *dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,overlappingPairCache,
			sol,collisionConfiguration);

	// XXX: do shit here
	
	ColladaPhysicsLoader loader(dynamicsWorld);
	bool loaded = loader.load(colladaFile.c_str());
	if(!loaded) 
	{
		String s = "Failed to load ";
		s.append(colladaFile);
		throw(runtime_error(s));
	}

	for(int i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
	{
		btCollisionObject *obj = dynamicsWorld->getCollisionObjectArray()[i];
		btRigidBody *body = btRigidBody::upcast(obj);

		object.push_back(body);

		//if(body && body->getMotionState())
		//{
		//	delete body->getMotionState();
		//}

		//dynamicsWorld->removeCollisionObject(obj);
	}

	delete dynamicsWorld;
	delete sol;
	delete overlappingPairCache;
	delete dispatcher;
	delete collisionConfiguration;

	return(object);
}
